from rest_framework.serializers import ModelSerializer, ListField, DictField, Serializer, BooleanField, CharField, ValidationError
from certificate_manager.models import Cert, Join, User, DepartRestrict, CertPic
from .join import NestedJoin
from datetime import date
from .certpic import CertPicSerializer
from .cate import CateSerializer

class InternalCertSerializer(ModelSerializer):
        class Meta:
                model = Cert
                fields = ['pk', 'cate', 'name', 'certpic_set', 'level', 'score', 'achieved_date', 'all_accept']
                read_only_fields = ['all_accept']
        

# 这里应当换成不同的名字，与Model中的Cert相区分, 所以这里面不仅有Cert，还可能有Join的信息
class CertSerializer(ModelSerializer):
        join_list = ListField(
                child=NestedJoin()
        )
        pics = CertPicSerializer(many=True, required=True)

        class Meta:
                model = Cert
                fields = ['pk', 'cate', 'name', 'level', 'score', 'achieved_date', 'pics', 'join_list', 'all_accept']
                extra_kwargs = { 'join_list': { 'read_only': True } }

        def create(self, validated_attr):
                # 我们在这里创建对象，同时需要Transaction
                join_list = validated_attr['join_list']
                pics = validated_attr['pics']

                attr_for_cert = validated_attr
                del attr_for_cert['join_list']
                del attr_for_cert['pics']

                cert = Cert.objects.create(**attr_for_cert) # 在这行之前需要将所有无关变量全部删除
                
                # 然后创建关系列表
                for record in join_list:
                        user = User.objects.get(uid=record['uid'])
                        join = Join.objects.create(cert=cert, user=user, restrict=record['restrict'], play_role_imp=record['play_role_imp'])
                        join.save()

                # 创建图片关系列表
                for pic in pics:
                        p = CertPic.objects.create(name=pic['name'], cert=cert)
                        p.save()

                cert.save()
                return cert

        def validate(self, attrs):
                all_extra_fields = Cert.EXTRA_FIELDS
                ccate = attrs['cate'] # 这是收集时的collect cate
                cate = ccate.cate # 我们要获取最根本的配置
                filted_set = all_extra_fields & attrs.keys()
                if cate.collect_part not in filted_set:
                        raise ValidationError(('Cert extra field not valid', filted_set) )
                
                # 下面我们要检查join_list里面的人是否符合要求
                # 首先统计出每个Department里面有多少人，然后检查department和人数情况    
                mem = {}
                join_partition_cnt = 0
                for join in attrs['join_list']:
                        restrict = join['restrict']
                        uid = join['uid']
                        if restrict not in mem:
                                mem[restrict] = set()
                        mem[restrict].add(uid)

                        join_partition_cnt += join['play_role_imp']

                # 检查play_role_imp字段是否和为100
                if join_partition_cnt != 100:
                        raise ValidationError(f'Join play_role_imp sum not equal to 100, current sum is {join_partition_cnt}')


                # 下面检查人数是否符合限制restrict要求
                for restrict in cate.departrestrict_set.all():
                        uid_set_len = len(mem[restrict])
                        if uid_set_len >= restrict.people_limit_min and uid_set_len <= restrict.people_limit_max:
                                pass # ok
                                del mem[restrict]
                        else:
                                raise ValidationError('join number retrict not fulfill')

                if len(mem) != 0:
                    # 说明有奇怪的东西混进来了
                    raise ValidationError('join restrict not fulfill')

                return attrs

        def to_representation(self, cert):
                join_list = NestedJoin(cert.join_set, many=True).data
                ser_dict = InternalCertSerializer(cert).data
                ser_dict['join_list'] = join_list
                ser_dict['cate_name'] = cert.cate.cate.name
                # level我们要替换成中文的
                ser_dict['level'] = str(cert.level) if cert.level else None
                # 将cert也序列化出来
                ser_dict['cate'] = CateSerializer(cert.cate.cate).data
                ser_dict['certpic_set'] = map(lambda x: CertPic.objects.get(pk=x).name, ser_dict['certpic_set'])
                return ser_dict

class JoinChangeSerializer(Serializer):
        approve = BooleanField()
        msg = CharField(max_length=100, allow_blank=True)

        def validate(self, attrs):
                if attrs['approve'] == False:
                        msg = attrs['msg']
                        if not ( len(msg) >= 1 and len(msg) <= 100):
                                raise ValidationError('if you want to reject this join request, please give a reason. (length in 1 to 100)')
                return attrs
